package com.cat.model.biz.service.api.impl;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Random;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alonew.core.commons.util.secure.MD5Util;
import com.alonew.db.dao.TxCommonDAO;
import com.alonew.json.JSONException;
import com.alonew.json.JSONObject;
import com.cat.model.biz.service.api.LoginService;
import com.cat.model.biz.service.bs.SmsBS;
import com.cat.model.common.enumerator.UnsupportSmsPhonePrefixEnum;
import com.cat.model.common.model.common.AccountVO;
import com.cat.model.common.model.common.DeviceInfoVO;
import com.cat.model.common.model.common.PhoneChcekCodeVO;
import com.cat.model.common.model.common.UserInfoVO;
import com.cat.model.common.model.common.UserPhoneVO;
import com.cat.model.common.model.common.UserTokenVO;
import com.cat.model.common.util.Constant;
import com.cat.model.common.util.ErrorCode;
import com.cat.model.common.util.LoggerManager;
import com.cat.model.dao.mapper.ModelMapper;
import com.cat.model.dao.mapper.UserInfoMapper;

@Service("loginService")
public class LoginServiceImpl implements LoginService{	
	@Autowired
	private TxCommonDAO txCommonDAO;
	
	@Autowired
	private UserInfoMapper userMapper;
	
	@Autowired
	private SmsBS smsBS;
	
	@Autowired
	private ModelMapper modelMapper;
	
	@Override
	public String regDeviceInfo(DeviceInfoVO deviceInfo) {
		addOrUpdDeviceInfo(deviceInfo);	
		return ErrorCode.OK.response();
	}
	
	private void addOrUpdDeviceInfo(DeviceInfoVO deviceInfo){
		if(deviceInfo.getId() != null){
			txCommonDAO.updateById(deviceInfo, "deviceType", "lastUserId",  "pushToken");
			return;
		}
		
		DeviceInfoVO existDevice = userMapper.getDeviceInfo(deviceInfo.getDeviceId());
		if(existDevice != null){
			deviceInfo.setId(existDevice.getId());
			txCommonDAO.updateById(deviceInfo, "deviceType", "lastUserId", "pushToken");
		}else{
			txCommonDAO.insert(deviceInfo);
		}
	}
	
	@Override
	public String preLoginByPhone(String deviceId, String phone, String type) {		
		if (!isPhoneLengthValid(phone)) { // 电话号码非法
			LoggerManager.error.info("phone not valie|" + phone);
			return ErrorCode.PHONE_INVALID.response();
		}

		if (isPhoneSendSmsUnsupport(phone)) { // 电话号码不支持下发短信
			LoggerManager.error.info("phone not support send sms|" + phone);
			return ErrorCode.PHONE_SENDSMS_UNSUPPORT.response();
		}

		sendCheckCode(phone, type);
		
		return ErrorCode.OK.response();
	}

	private void sendCheckCode(String phone, String type) {
		PhoneChcekCodeVO phoneCheckCode = userMapper.getPhoneCheckCode(phone);
		if(null == phoneCheckCode){
			phoneCheckCode = new PhoneChcekCodeVO();
			phoneCheckCode.setPhoneNo(phone);
			txCommonDAO.insert(phoneCheckCode);
		}
		
		//2.生成验证码、下发短信
		String checkCode = phoneCheckCode.getCheckCode();
		if(StringUtils.isEmpty(phoneCheckCode.getCheckCode())
				|| phoneCheckCode.getCheckCodeExpire() < new Date().getTime()){
			checkCode = this.generatePassworld();
		}
		
		phoneCheckCode.setCheckCode(checkCode);
		long expireTime = 1000*60*30;//30分钟过期
		phoneCheckCode.setCheckCodeExpire(new Date().getTime() + expireTime);
		
		txCommonDAO.updateById(phoneCheckCode, "checkCode", "checkCodeExpire");
		
		if(Constant.CHECK_CODE_CALL.equals(type)){
			smsBS.sendCallBYTaobao(phone, checkCode);
		}else{
			smsBS.sendCheckCodeSMS(phone, checkCode);
		}
	}
	
	@Override
	public String loginByPhone(String deviceId, String phoneNo, String checkCode, String password,String nickName,Long inviterId
			) {
		DeviceInfoVO device = userMapper.getDeviceInfo(deviceId);
		//1.校验验证码合法性
		PhoneChcekCodeVO phoneCheckCode = userMapper.getPhoneCheckCode(phoneNo);
		
		long curTime = new Date().getTime();
		if(null == phoneCheckCode || !"15260223203".equals(phoneCheckCode.getPhoneNo())){
			if(null == phoneCheckCode || !checkCode.equals(phoneCheckCode.getCheckCode())){
				return ErrorCode.CHECK_CODE_INVAILD.response();
			}
			if(curTime > phoneCheckCode.getCheckCodeExpire()){
				return ErrorCode.CHECK_CODE_EXPIRE.response();
			}
		}		
		
		UserPhoneVO userPhone = userMapper.getUserPhone(phoneNo);
		/*if(userPhone!=null){
			return ErrorCode.USER_EXIST.response();
		}*/
		if(null == userPhone){
			UserInfoVO userInfo = new UserInfoVO();
			userInfo.setPassword(MD5Util.encode(password));
			userInfo.setCreateTime(new Date());
			if(device != null){
				userInfo.setClientChannel(device.getDeviceType());
				userInfo.setDeviceId(deviceId);
			}
			userInfo.setNickName(nickName);
			userInfo.setInviterId(inviterId);
			userInfo.setUserLevel("0");//注册用户
			
			txCommonDAO.insert(userInfo);
			
			userPhone = new UserPhoneVO();
			userPhone.setUserId(userInfo.getId());
			userPhone.setPhoneNo(phoneNo);
			txCommonDAO.insert(userPhone);
		}
		
		AccountVO account = modelMapper.getAccount(userPhone.getUserId());
		if(account==null){
			//新增账户信息
			account = new AccountVO();
			account.setUserId(userPhone.getId());
			account.setAvailBalance(new BigDecimal("0"));
			account.setBalance(new BigDecimal("0"));
			txCommonDAO.insert(account);
		}
		
		UserInfoVO user = userMapper.getUserInfo(userPhone.getUserId());
		if(StringUtils.isNotEmpty(password)){
			user.setPassword(MD5Util.encode(password));
			txCommonDAO.updateById(user, "password");
		}
				
		//2.生成token
		UserTokenVO userToken = this.applyToken(userPhone.getUserId(), deviceId, userPhone.getPhoneNo());
		
		getOrInitDeviceInfo(deviceId, userPhone.getUserId());
		
		JSONObject json = ErrorCode.OK.responseJSON();
		try {
			JSONObject infoJson = new JSONObject();
			infoJson.put("userId", userPhone.getUserId());
			infoJson.put("token", userToken.getToken());
			infoJson.put("refreshToken", userToken.getRefreshToken());
			
			json.put("data", infoJson);
		} catch (JSONException e) {
			return ErrorCode.SERVER_ERROR.response();
		}
		
		return json.toString();
	}
	
	@Override
	public String loginByPhonePass(String deviceId, String phoneNo, String password) {
		UserPhoneVO userPhone = userMapper.getUserPhone(phoneNo);
		if(null == userPhone){
			return ErrorCode.USER_NOT_EXIST.response();
		}
		
		UserInfoVO user = userMapper.getUserInfo(userPhone.getUserId());
		if(null == user){
			return ErrorCode.USER_NOT_EXIST.response();
		}
		
		if(!MD5Util.encode(password).equals(user.getPassword())){
			return ErrorCode.PASSWORD_ERROR.response();
		}
				
		//2.生成token
		UserTokenVO	userToken = this.applyToken(userPhone.getUserId(), deviceId, userPhone.getPhoneNo());

		getOrInitDeviceInfo(deviceId, userPhone.getUserId());
		
		JSONObject json = ErrorCode.OK.responseJSON();
		try {
			JSONObject infoJson = new JSONObject();
			infoJson.put("userId", userPhone.getUserId());
			infoJson.put("token", userToken.getToken());
			infoJson.put("refreshToken", userToken.getRefreshToken());
			
			json.put("data", infoJson);
		} catch (JSONException e) {
			return ErrorCode.SERVER_ERROR.response();
		}
		
		return json.toString();
	}
	
	@Override
	public String renewalToken(String oldRefreshToken){
		Date date = new Date();
		//1.校验refreshToken合法性
		UserTokenVO userToken = userMapper.getUserTokenByRefreshToken(oldRefreshToken);
		if(null == userToken || userToken.getRefreshTokenExpire() < date.getTime()){
			return ErrorCode.REFRESH_TOKEN_EXPIRE.response();
		}
		
		//2.重新生成token
		String token = this.createToken(userToken.getUserId());
		long tokenExpire = date.getTime() + getTokenExpireTimes();//3天过期
		String refreshToken = this.createToken(userToken.getUserId());
		long refreshTokenExpire = date.getTime() + getRefreshExpireTimes();//30天过期
		
		userToken.setToken(token);
		userToken.setTokenExpire(tokenExpire);
		userToken.setRefreshToken(refreshToken);
		userToken.setRefreshTokenExpire(refreshTokenExpire);
		
		txCommonDAO.updateById(userToken, "token", "tokenExpire", "refreshToken", "refreshTokenExpire");
		
		JSONObject json = ErrorCode.OK.responseJSON();
		try {
			JSONObject infoJson = new JSONObject();
			infoJson.put("token", token);
			infoJson.put("refreshToken", refreshToken);
			
			json.put("data", infoJson);
		} catch (JSONException e) {
			return ErrorCode.SERVER_ERROR.response();
		}
		
		return json.toString();
	}
	
	@Override
	public String logout(String token) {
		UserTokenVO userToken = userMapper.getUserTokenByToken(token);
		if(null == userToken){
			return ErrorCode.OK.response();
		}
		
		Date date = new Date();
		userToken.setTokenExpire(date.getTime());
		userToken.setRefreshTokenExpire(date.getTime());
		
		txCommonDAO.updateById(userToken, "tokenExpire", "refreshTokenExpire");
		
		return ErrorCode.OK.response();
	}
	
	@Override
	public String preBindPhoneNo(String token, String newPhoneNo, String type){
		Date date = new Date();
		//token过期
		UserTokenVO userToken = userMapper.getUserTokenByToken(token);
		if(null == userToken || userToken.getTokenExpire() < date.getTime()){
			return ErrorCode.TOKEN_EXPIRE.response();
		}
		
		//手机号码已绑定
		UserPhoneVO userPhone = userMapper.getUserPhone(newPhoneNo);
		if(userPhone != null && !userPhone.getId().equals(userToken.getUserId())){
			return ErrorCode.PHONE_BINDED.response();
		}
						
		if (!isPhoneLengthValid(newPhoneNo)) { // 电话号码非法
			LoggerManager.error.info("phone not valie|" + newPhoneNo);
			return ErrorCode.PHONE_INVALID.response();
		}

		if (isPhoneSendSmsUnsupport(newPhoneNo)) { // 电话号码不支持下发短信
			LoggerManager.error.info("phone not support send sms|" + newPhoneNo);
			return ErrorCode.PHONE_SENDSMS_UNSUPPORT.response();
		}

		sendCheckCode(newPhoneNo, type);
						
		return ErrorCode.OK.response();
	}
	
	@Override
	public String bindPhoneNo(String token, String newPhoneNo, String checkCode, String password){
		Date date = new Date();
		//token过期
		UserTokenVO userToken = userMapper.getUserTokenByToken(token);
		if(null == userToken || userToken.getTokenExpire() < date.getTime()){
			return ErrorCode.TOKEN_EXPIRE.response();
		}
		
		//校验验证码合法性
		//1.校验验证码合法性
		PhoneChcekCodeVO phoneCheckCode = userMapper.getPhoneCheckCode(newPhoneNo);
		if(null == phoneCheckCode){
			return ErrorCode.CHECK_CODE_INVAILD.response();
		}
		
		long curTime = new Date().getTime();
		
		if(!"15260223203".equals(phoneCheckCode.getPhoneNo())){
			if(!checkCode.equals(phoneCheckCode.getCheckCode())){
				return ErrorCode.CHECK_CODE_INVAILD.response();
			}
			if(curTime > phoneCheckCode.getCheckCodeExpire()){
				return ErrorCode.CHECK_CODE_EXPIRE.response();
			}
		}
		
		UserInfoVO user = userMapper.getUserInfo(userToken.getUserId());
		if(null == user){
			return ErrorCode.USER_NOT_EXIST.response();
		}
		
		if(!MD5Util.encode(password).equals(user.getPassword())){
			return ErrorCode.PASSWORD_ERROR.response();
		}
		
		//修改用户的手机号码
		UserPhoneVO userPhone = userMapper.getUserPhoneByUserId(userToken.getUserId());
		if(null == userPhone){
			userPhone = new UserPhoneVO();
			userPhone.setUserId(userToken.getUserId());
			userPhone.setPhoneNo(newPhoneNo);
			txCommonDAO.insert(userPhone);
		}else{
			userPhone.setPhoneNo(newPhoneNo);
			txCommonDAO.updateById(userPhone, "phoneNo");
		}
		
		return ErrorCode.OK.response();
	}
	
	/**
	 * 修改密码
	 */
	public String updatePassword(Long userId,String phoneNo, String password , String checkCode){
		//1.校验验证码合法性
		PhoneChcekCodeVO phoneCheckCode = userMapper.getPhoneCheckCode(phoneNo);
		
		long curTime = new Date().getTime();
		if(null == phoneCheckCode || !"15260223203".equals(phoneCheckCode.getPhoneNo())){
			if(null == phoneCheckCode || !checkCode.equals(phoneCheckCode.getCheckCode())){
				return ErrorCode.CHECK_CODE_INVAILD.response();
			}
			if(curTime > phoneCheckCode.getCheckCodeExpire()){
				return ErrorCode.CHECK_CODE_EXPIRE.response();
			}
		}
		UserInfoVO userInfo = userMapper.getUserInfo(userId);
		if(userInfo==null){
			return ErrorCode.USER_NOT_EXIST.response();
		}
		userInfo.setPassword(MD5Util.encode(password));
		txCommonDAO.updateById(userInfo, "password");
		return ErrorCode.OK.response();
	}
	private UserTokenVO applyToken(long userId, String deviceId, String phoneNo){
		Date date = new Date();
		String token = this.createToken(userId);
		long tokenExpire = date.getTime() + getTokenExpireTimes();//24小时过期
		String refreshToken = this.createToken(userId);
		long refreshTokenExpire = date.getTime() + getRefreshExpireTimes();//10天过期
		UserTokenVO userToken = userMapper.getUserToken(userId);
		if(null == userToken){
			userToken = new UserTokenVO();
			userToken.setDeviceId(deviceId);
			userToken.setUserId(userId);
			userToken.setToken(token);
			userToken.setTokenExpire(tokenExpire);
			userToken.setRefreshToken(refreshToken);
			userToken.setRefreshTokenExpire(refreshTokenExpire);
			txCommonDAO.insert(userToken);			
		}else{
			userToken.setDeviceId(deviceId);
			userToken.setToken(token);
			userToken.setTokenExpire(tokenExpire);
			userToken.setRefreshToken(refreshToken);
			userToken.setRefreshTokenExpire(refreshTokenExpire);
			txCommonDAO.updateById(userToken, "deviceId", "token", "tokenExpire", "refreshToken", "refreshTokenExpire");
		}
		
		return userToken;
	}
	
	private DeviceInfoVO getOrInitDeviceInfo(String deviceId, Long userId) {
		DeviceInfoVO device = userMapper.getDeviceInfo(deviceId);
		if(null == device){
			device = new DeviceInfoVO();
			device.setDeviceId(deviceId);
			device.setDeviceType(Constant.USER_CLIENT_CHANNEL_UNKNOW);
		}
		
		device.setLastUserId(userId);
		this.addOrUpdDeviceInfo(device);
		return device;
	}
	
	private long getTokenExpireTimes() {
		return 1000*60*60*24*10l;
	}
	
	private long getRefreshExpireTimes() {
		return 1000*60*60*24*30l;
	}
	
	public String createToken(long uid) {
        String uuid = UUID.randomUUID().toString();
        String token = uid + "-" + uuid.replaceAll("-", "");
        return token;
    }

	private boolean isPhoneLengthValid(String phone) {
		try {
			Long phoneValue = Long.valueOf(phone);
			return phoneValue > 10000000000L;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	private boolean isPhoneSendSmsUnsupport(String phone) {
		for (UnsupportSmsPhonePrefixEnum prefixEnum : UnsupportSmsPhonePrefixEnum.values()) {
			if (phone.startsWith(prefixEnum.getPrefix())) {
				return true;
			}
		}
		return false;
	}
	
	
	public String generatePassworld() {
		return 100000 + new Random().nextInt(900000) + "";
	}
	
}
